package cn.concurrent.lock;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 实现ACS容器，CTRl+C 和CTRL+V 没有理解
 * @Author: lz
 * @Date: 2018/8/22 14:57
 * @Version 1.0
 */
public class MutextDemo {
	private static Mutex mutex = new Mutex();

	public static void main(String[] args) {

		for (int i = 0; i < 10; i++) {
			Thread thread = new Thread(() -> {
				mutex.lock();
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					mutex.unlock();
				}
			});
			thread.start();
		}
	}
}


 class Mutex implements Lock, java.io.Serializable {
	// Our internal helper class
	// 继承AQS的静态内存类
	// 重写方法
	private static class Sync extends AbstractQueuedSynchronizer {
		// Reports whether in locked state
		protected boolean isHeldExclusively() {
			return getState() == 1;
		}

		// Acquires the lock if state is zero
		public boolean tryAcquire(int acquires) {
			assert acquires == 1; // Otherwise unused
			if (compareAndSetState(0, 1)) {
				setExclusiveOwnerThread(Thread.currentThread());
				return true;
			}
			return false;
		}

		// Releases the lock by setting state to zero
		protected boolean tryRelease(int releases) {
			assert releases == 1; // Otherwise unused
			if (getState() == 0) throw new IllegalMonitorStateException();
			setExclusiveOwnerThread(null);
			setState(0);
			return true;
		}

		// Provides a Condition
		Condition newCondition() {
			return new ConditionObject();
		}

		// Deserializes properly
		private void readObject(ObjectInputStream s)
				throws IOException, ClassNotFoundException {
			s.defaultReadObject();
			setState(0); // reset to unlocked state
		}
	}

	// The sync object does all the hard work. We just forward to it.
	private final Sync sync = new Sync();
	//使用同步器的模板方法实现自己的同步语义
	public void lock() {
		sync.acquire(1);
	}

	public boolean tryLock() {
		return sync.tryAcquire(1);
	}

	public void unlock() {
		sync.release(1);
	}

	public Condition newCondition() {
		return sync.newCondition();
	}

	public boolean isLocked() {
		return sync.isHeldExclusively();
	}

	public boolean hasQueuedThreads() {
		return sync.hasQueuedThreads();
	}

	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
	}

	public boolean tryLock(long timeout, TimeUnit unit)
			throws InterruptedException {
		return sync.tryAcquireNanos(1, unit.toNanos(timeout));
	}
}

